#include "ESDecoder.h"
#include "../inc/Utils.h"

ESDecoder::ESDecoder()
{
	ESBuffer = (unsigned char*)malloc(MAX_FRAME_SIZE);
	memset(ESBuffer, 0, MAX_FRAME_SIZE);
	ESBufferFrame = (unsigned char*)malloc(MAX_FRAME_SIZE);
	memset(ESBufferFrame, 0, MAX_FRAME_SIZE);
	ESBufferOffset = 0;
	lostPacket = 0;
	codec = NULL;
	c = NULL;
	unpacker = NULL;

	recvThreadRunning = true;
	decodeThreadRunning = true;
	playFlag = PLAY;

	recvBuf = (char*)malloc(2048);

	av_register_all();
	avformat_network_init();

	lfds611_queue_new( &qs_pool, QUEUE_SIZE );
	lfds611_queue_new( &qs_packet, QUEUE_SIZE );
	for(int i = 0;i<QUEUE_SIZE;i++)
	{
		ESPacketBuffer *packetBuffer =(ESPacketBuffer*)malloc(sizeof(ESBuffer));;
		packetBuffer->packetBuffer =(unsigned char*)malloc(MAX_PAKCET_SIZE);
		memset(packetBuffer->packetBuffer, 0 , MAX_PAKCET_SIZE);
		lfds611_queue_use(qs_pool);
		lfds611_queue_enqueue( qs_pool, (void *)packetBuffer );
	}
}


ESDecoder::~ESDecoder(void)
{
	if(port != 0)
	{
		_print_log("Finished receiving. Closing socket.\n");
		close(RecvSocket);
	}
	if(recvThread != NULL)
	{
		//TerminateThread(startThread, 0);
		recvThreadRunning = false;
		pthread_join(recvThread, NULL);

		recvThread = NULL;
	}

	if(decodeThread != NULL)
	{
		//TerminateThread(decodeThread, 0);
		decodeThreadRunning = false;
		pthread_join(decodeThread, NULL);
		decodeThread = NULL;
	}
	if(unpacker != NULL)
		delete unpacker;

	free(ESBufferFrame);
	free(recvBuf);


	if(c != NULL)
	{
		avcodec_close(c);
		av_free(c);
	}


	av_frame_free(&frame);

	if(frameBGR != NULL)
		avpicture_free((AVPicture*) frameBGR);
	avformat_network_deinit();

	if(qs_pool != NULL && qs_packet != NULL)
	{
		PSPacketBuffer *buffer = NULL;
		int free_count = 0;
		lfds611_queue_use(qs_pool);

		while(LFDS_SUCCESS == lfds611_queue_dequeue( qs_pool, (void **) &buffer))
		{
			if(buffer->packetBuffer != NULL)
			{
				free(buffer->packetBuffer);
				free_count ++;
				//printf("pool_free_count:%d\n", free_count);
			}
		}
		lfds611_queue_use(qs_packet);
		while(LFDS_SUCCESS == lfds611_queue_dequeue( qs_packet, (void **) &buffer))
		{
			if(buffer->packetBuffer != NULL)
			{
				free(buffer->packetBuffer);
				free_count ++;
				//printf("packet_free_count:%d\n", free_count);
			}
		}
	}
	else
	{// no need for freeing queue;
	}

	_print_log("released\n");
}



void ESDecoder::startRecvThread()
{
	//FILE* fd = fopen("d:/00_28_02.h264", "rb");
	while(recvThreadRunning == true)
	{
		if(playFlag == PLAY)
		{
		}
		else if(playFlag == PAUSE)
		{
			usleep(NORMAL_WAIT_TIME);
			continue;
		}
		else if(playFlag == STOP)
		{
			break;
		}
		else
		{
			_print_log("illegal playflag\n");
			break;
		}

		int readLength = 0;

		//_print_log("Receiving datagrams...\n");
		struct sockaddr_in clientAddr;
		socklen_t len = sizeof(clientAddr);
		readLength = recvfrom(RecvSocket, recvBuf, 1500, 0, (struct sockaddr*)&clientAddr, &len);

		if (readLength == -1) {
			perror( "recvfrom ");
			//				_print_log("recvfrom failed with error %d\n", WSAGetLastError());
			continue;
		}
		else if(readLength == 0)
		{
			_print_log("End of stream.\n");

			break;
		}
		else
		{

		}

		//readLength = 1024;
		//fread(recvBuf, 1, 1024, fd);

		progress += readLength;
		ESPacketBuffer *buffer;
		lfds611_queue_use(qs_pool);
		while(LFDS_SUCCESS != lfds611_queue_dequeue( qs_pool, (void **) &buffer))
		{
			if(recvThreadRunning != true)
				return;
			printf("dequeue failed\n");
			_print_log("dequeue failed\n");
			//lostPacket ++;
			usleep(NORMAL_WAIT_TIME);
		}
		memcpy(buffer->packetBuffer, recvBuf, readLength);
		buffer->bufferSize = readLength;
		lfds611_queue_use(qs_packet);
		while(LFDS_SUCCESS != lfds611_queue_enqueue( qs_packet, (void *) buffer))
		{
			if(recvThreadRunning != true)
				return;
			lostPacket ++;
			usleep(NORMAL_WAIT_TIME);
		}
	}
}


void ESDecoder::startDecodeThread()
{
	while(qs_pool == NULL || qs_packet == NULL)
		usleep(NORMAL_WAIT_TIME * 100);

	av_init_packet(&avpkt);

	codec = avcodec_find_decoder(AV_CODEC_ID_H264);
	if(codec == NULL)
	{
		_print_log("Codec not found.\n");
	}
	c = avcodec_alloc_context3(codec);
	if(c == NULL)
	{
		_print_log("could not allocate video codec context\n");
	}
	if(avcodec_open2(c, codec, NULL) < 0)
	{
		_print_log("could not open codec\n");
	}
	frame = av_frame_alloc();
	if(frame == NULL)
	{
		_print_log("could not allocate video frame\n");
	}
	frameBGR = av_frame_alloc();
	if(frameBGR == NULL)
	{
		_print_log("could not allocate video frame\n");
	}

	unsigned char h264 = 96;
	unpacker = new RTPUnpacker(h264);
	int currentPacketSize = 0;

	while(decodeThreadRunning == true)
	{
		if(playFlag == PLAY)
		{
		}
		else if(playFlag == PAUSE)
		{
			usleep(NORMAL_WAIT_TIME);
			continue;
		}
		else if(playFlag == STOP)
		{
			break;
		}
		else
		{
			_print_log("illegal playflag\n");
			break;
		}

		ESPacketBuffer *buffer;
		lfds611_queue_use(qs_packet);
		while(LFDS_SUCCESS != lfds611_queue_dequeue( qs_packet, (void **) &buffer))
		{
			if(decodeThreadRunning != true)
				return;
			usleep(NORMAL_WAIT_TIME);
		}
		//printf("PSFrameOffset:%d, bufferSize:%d\n", PSFrameOffset,buffer->bufferSize );
		if(ESBufferOffset > 900 * 1024)
		{// packet lost too much, barely to demux, reset the frameoffset to prevent the memory error.
			ESBufferOffset = 0;
			_print_log("packet lost too much, reset the buffer.\n");
		}
		memcpy(ESBuffer + ESBufferOffset, buffer->packetBuffer, buffer->bufferSize);
		//printf("%d\n", buffer->bufferSize);
		ESBufferOffset += buffer->bufferSize;
		currentPacketSize = buffer->bufferSize;
		//printf("offset:%d\n", PSFrameOffset);
		lfds611_queue_use(qs_pool);
		while(LFDS_SUCCESS != lfds611_queue_enqueue( qs_pool, (void *) buffer))
		{
			if(decodeThreadRunning != true)
				return;
			lostPacket ++;
			usleep(NORMAL_WAIT_TIME);
		}

		int count = 0;

		int outsize = 0;
		char* result = unpacker->Parse_RTP_Packet((BYTE*)ESBuffer + ESBufferOffset - currentPacketSize,
			currentPacketSize, &outsize); 


		if(outsize > 0 && result != NULL)
		{
			//							SYSTEMTIME wtm;
			//GetLocalTime(&wtm);
			//printf("frame:%d:%d:%d.%d\n", wtm.wHour, wtm.wMinute, wtm.wSecond, wtm.wMilliseconds);
			//printf("%d\n", outsize);
			memcpy(ESBufferFrame, result, outsize);
			count = outsize;
			ESBufferOffset = 0;

			avpkt.data = ESBufferFrame;
			avpkt.size = count;
		}
		else
		{
			continue;
		}

		int len = 0, got_frame = 0;

		len = avcodec_decode_video2(c, frame, &got_frame, &avpkt);
		if(len < 0)
		{
			_print_log("Error while decoding frame\n");
			continue;
		}

		if(got_frame)
		{
			//_print_log("%d, %d\n", width, height);
			//_print_log("success\n");
			//FILE* fd = fopen("d://1.pgm", "w");
			//fprintf(fd, "P5\n%d %d\n%d\n", width,height,255);
			//for(int i =0;i<height;i++)
			//	fwrite(frame->data[0] + i* frame->linesize[0] , 1, width, fd);
			//fclose(fd);
			if(frameBGR->data[0] == NULL)
			{
				width = frame->width;
				height = frame->height;
				pRGBData = (char*)malloc(width * height * 4);
				pSwsCtxBGR32 = sws_getContext(frame->width, frame->height,AV_PIX_FMT_YUV420P, width, height, AV_PIX_FMT_RGB32,SWS_BILINEAR,NULL,NULL,NULL);

				avpicture_alloc((AVPicture*)frameBGR, AV_PIX_FMT_RGB32, width, height);
			}
			frameBGR->width = width;
			frameBGR->height = height;
			int ret = sws_scale(pSwsCtxBGR32, frame->data,frame->linesize,0, frame->height,frameBGR->data,frameBGR->linesize);
			if(frameBGR->height != ret)
			{
				_print_log("sws_scale failed\n");
				continue;
			}

			frameInfo.width = width;
			frameInfo.height = height;
			(*DecodeCBFun)((char*)frameBGR->data[0], width * height * 4, &frameInfo, pUser);

		}
		av_free_packet(&avpkt);		
	}

}
